#include <iostream>
#include <mysql/mysql.h>
#include <unistd.h>
#include <string>
       #include <fcntl.h>
#include "common.hpp"
#include <jsoncpp/json/json.h>
#include"../log.hpp"
#define NOT_STD -1
#define PWD_ERR -2
#define USERNAME_NOT_FOUND -3
#define SQL_CON_ERR -4
#define QUERY_ERR -5
#define RES_ERR -6
#define JSON_ERR -7
const char *username_err = "用户名错误!";
const char *userpwd_err = "密码错误!";
using namespace std;
string newtoken;

/*
    用于处理登陆按钮cgi接口,
    对用户名密码进行数据库查询,
    匹配正确返回成功码和该用户的博客主页url,
    匹配失败返回对应错误码
*/

// 通过method来获取参数的方法
bool getQueryString(std::string &query)
{
    std::string method;
    method = getenv("METHOD");
    if ("GET" == method)
    {
        // 不对get请求处理
        return false;
    }
    else if ("POST" == method)
    {

        // POST方法参数通过管道传
        if (getenv("CONTENT_LENGTH") == NULL)
        {
            std::cerr << "获取正文长度参数失败!!!" << std::endl;
            return false;
        }
        int len = atoi(getenv("CONTENT_LENGTH"));
        // std::cerr<<"DEBUG:"<<len<<std::endl;
        char ch;
        while (len)
        {
            ssize_t n = read(0, &ch, 1);
            if (n > 0)
            {
                query.push_back(ch);
                len--;
            }
            else
            {
                return false;
            }
        }
        std::cerr << "DEBUG: 读取正文参数成功!!" << std::endl;
        return true;
    }
    return false;
}

// 校验登陆用户名密码,对表进行查询
int mysql_login(const std::string &name, const std::string &pwd)
{
    stringstream ss;
    // 检查密码是否符合规范
    if (name.size() == 0 || pwd.size()< 6)
        return NOT_STD;

    std::cerr << "DEBUG: 密码符合规范: " << name << "-" << pwd << std::endl;

    MYSQL *conn = mysql_init(nullptr);
    if (nullptr == mysql_real_connect(conn, "127.0.0.1", "ldcwd", "123456", "httptest", 3306, nullptr, 0))
    {
        std::cerr << " mysql connect error !!" << std::endl;
        return SQL_CON_ERR;
    }
    std::cerr << "sql connect success!! " << std::endl;

    // 验证用户名
    std::string sql = "select * from users where name = \'" + name + "\';"; //
    if (mysql_query(conn, sql.c_str()))
    {
        // 查询失败
        std::cerr << "查询失败" << std::endl;
        return QUERY_ERR;
    }
    std::cerr << "DEBUG: 查询成功!!" << std::endl;
    // 把结果提取到结果集中再对用户名 密码进行校验
    MYSQL_RES *res = mysql_store_result(conn);
    if (res != NULL)
    {
        // 提取成功
        std::cerr << "DEBUG: 提取成功!" << std::endl;
        int rows = mysql_num_rows(res);     // 1.获取行
        int fields = mysql_num_fields(res); // 2.获取列

        // 获取内容行对应的char**
        MYSQL_ROW row_content = mysql_fetch_row(res);
        if (row_content == nullptr)
        {
            std::cerr << "DEBUG SQL: 行内容为空!" << std::endl;
            return USERNAME_NOT_FOUND;
        }
        // 内容行存在
        std::cerr << "DEBUG SQL: 行内容不为空!" << std::endl;

        // 1  '张三'  '12345'
        string user_id=row_content[0];
        std::string user_name = row_content[1];
        std::string user_pwd = row_content[2];
        std::cerr << "DEBUG QUERY RESULT: ID :" <<user_id  << " - " << "name:"<<user_name<< std::endl;

        if (name == user_name)
        {
            // 再对密码进行判断
            if (pwd == user_pwd)
            {
                //生成token,更新到mysql,把token返回给前端
                //1.生成
                newtoken=AuthMiddleware::generate_random_token(user_id);

                cerr<<"DEBUG: TOKEN:"<<newtoken;
                cerr<<"DEBUG---------------------------";
                //2.更新到mysql的sessions
                //3. 更新有效时间
                 ss<<"update sessions set token="<<"\'"<<newtoken<<"\'"\
                 <<",expires_at=DATE_ADD(NOW(),INTERVAL 1 DAY)"<<" where user_id ="<<user_id<<";";
                 cerr<<"DEBUG: update SQL: "<<ss.str()<<endl;
                if( mysql_query(conn,ss.str().c_str()))
                {
                    return QUERY_ERR;
                }

               return 0;
            }
            else
            {
                // 密码错误
                return PWD_ERR;
            }
        }
        else
        {
            return USERNAME_NOT_FOUND;
        }

        // //遍历打印
        //  for(int i=0;i<fields;i++)
        // {
        //     std::cerr<<fields_arr[i].name<<"\t";
        // }
        // std::cerr<<std::endl;

        // for(int i=0;i<fields;i++)
        // {
        //     std::cerr<<row[i]<<"\t";
        // }
        // std::cerr<<std::endl;
    }
    else
    {
        // 提取失败
        std::cerr << "ERROR: 提取结果集失败!!" << std::endl;
        return RES_ERR;
    }
    mysql_free_result(res);
    mysql_close(conn);
    return 0;
}

// 通过返回码code构建一个可返回的string
std::string buildString(const int &code)
{
    std::string ret;
    // 返回登陆成功json字符串
    Json::Value v; // 万能对象结构体
    switch (code)
    {
    case 0:
        // 把对应的键值对写入 万能对象结构体
        v["success"] = true;
        v["url"] = "http://47.99.68.28:8888/blog/blog_html/blog_home.html"; // 这里的url需要写全吗?
        v["message"] = "登陆成功!!";
        v["token"]=newtoken;
        break;
    case USERNAME_NOT_FOUND:
        v["success"] = false;
        v["message"] = "用户名不存在!";
        break;
    case PWD_ERR:
        v["success"] = false;
        v["message"] = "密码错误!!";
        break;
    case NOT_STD:
        v["success"] = false;
        v["message"] = "密码不规范!请输入6~12位密码";
        break;
    case QUERY_ERR:
        v["success"] = false;
        v["message"] = "指令错误!!!";
        break;
    case SQL_CON_ERR:
        v["success"] = false;
        v["message"] = "连接错误!!!";
        break;
    case RES_ERR:
        v["success"] = false;
        v["message"] = "结果集错误!!!";
        break;
    }
    // 序列化JSON得到一个串
    Json::StyledWriter w;
    ret = w.write(v);
    return ret;
}
int main()
{
    // std::cout<<mysql_get_client_info()<<std::endl;

    // 1.获取参数
    std::string query_string;
    if (getQueryString(query_string))
    {
        std::cerr << "DEBUG: json字符串长什么样:  " << query_string << std::endl;
        // post请求不需要对url进行解码

        // 对json字符串进行解析(反序列化)
        Json::Value v;
        Json::Reader r;
        bool success = r.parse(query_string, v);
        
        if (success)
        {
            std::string name=v["username"].asString();
        std::string pwd=v["userpwd"].asString();
         int n = mysql_login(name, pwd);
        std::string ret = buildString(n);

        // 直接向标准输出流输出(已被管道文件重定向)
        std::cout << ret;
        }
        else
        {
            // 解析失败
            std::cerr << "json ERROR!" << std::endl;
                return JSON_ERR;
        }

    }
    else
    {
        // 获取参数失败
        return -1;
    }
    return 0;
}